package ace.cmp.spring.data.jdbc.querydsl.core.converter.impl;

import ace.cmp.core.model.PageDto;
import ace.cmp.core.model.PageResultDto;
import ace.cmp.spring.data.jdbc.querydsl.core.converter.PageConverter;
import java.util.List;
import java.util.function.Function;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.QPageRequest;

/**
 * @author caspar
 * @date 2023/4/14 15:43
 */
public class PageConverterImpl implements PageConverter {

  public static PageConverter INSTANCE = new PageConverterImpl();

  @Override
  public <T> PageResultDto<T> to(Page<T> page) {
    return PageResultDto.<T>builder()
        .total(page.getTotalElements())
        .totalPage(page.getTotalPages())
        .data(page.getContent())
        .hasNext(page.hasNext())
        .hasPrevious(page.hasPrevious())
        .page(page.getNumber())
        .build();
  }

  @Override
  public <T, R> PageResultDto<R> to(Page<T> page, Function<T, R> mapper) {
    return this.to(page.map(mapper));
  }

  @Override
  public <T, R> PageResultDto<R> toMapperList(Page<T> page, Function<List<T>, List<R>> mapper) {
    List<T> content = page.getContent();
    List<R> newContent = mapper.apply(content);
    return PageResultDto.<R>builder()
        .total(page.getTotalElements())
        .totalPage(page.getTotalPages())
        .data(newContent)
        .hasNext(page.hasNext())
        .hasPrevious(page.hasPrevious())
        .page(page.getNumber())
        .build();
  }

  @Override
  public PageRequest toPageRequest(PageDto page) {
    return PageRequest.of(page.getPage(), page.getSize());
  }

  @Override
  public QPageRequest toQPageRequest(PageDto page) {
    return QPageRequest.of(page.getPage(), page.getSize());
  }

  @Override
  public PageDto toPageDto(Pageable pageable) {
    return PageDto.builder()
        .page(pageable.getPageNumber())
        .size(pageable.getPageSize())
        .build();
  }

  @Override
  public <T, R> Page<R> toPage(
      PageResultDto<T> pageResultDto, Pageable pageable, Function<T, R> mapper) {
    Page<T> tPage = new PageImpl<T>(pageResultDto.getData(), pageable, pageResultDto.getTotal());
    return tPage.map(mapper);
  }

  @Override
  public <T> Page<T> toPage(PageResultDto<T> pageResultDto, Pageable pageable) {
    return this.toPage(pageResultDto, pageable, p -> p);
  }

  @Override
  public <T, R> Page<R> toPageMapperList(Page<T> page, Pageable pageable,
      Function<List<T>, List<R>> mapper) {
    List<T> content = page.getContent();
    List<R> newContent = mapper.apply(content);
    return new PageImpl<R>(newContent, pageable, page.getTotalElements());
  }
}
